package com.tg.app.playback;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.os.SystemClock;
import android.text.TextUtils;

import com.appbase.custom.oss.OnGetOssResultCallback;
import com.demo.view.TimeRuleView;
import com.tg.app.camera.Camera;
import com.tg.app.statistics.TangeVideoPlayStatistics;
import com.tange.base.toolkit.DateUtil;
import com.tg.appcommon.android.TGLog;
import com.tg.data.http.entity.AVFrames;
import com.tg.data.http.entity.EventData;
import com.tg.data.http.entity.EventMessageBean;
import com.tg.data.media.CloudDecodeThread;
import com.tg.data.media.OnCloudDecodeListener;
import com.tange.core.backend.service.http.ClientObserver;
import com.tg.network.socket.http.TGHttp;
import com.tg.oss.OssMgr;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;

import io.reactivex.schedulers.Schedulers;

/**
 * Describe:
 * Created by Rance Rang on 2019-09-15.
 * <p>
 * Copyright (c) Tange.Inc All rights reserved.
 */
public class CloudPlayback extends TGPlayback implements OnCloudDecodeListener, OnGetOssResultCallback {
    private static final String TAG = "CloudPlayback";
    private LinkedBlockingQueue<Long> fileTimeQueue = new LinkedBlockingQueue<>();
    private boolean isGetCloudThreadRunning;
    private Thread getCloudThread;
    private final CloudDecodeThread cloudDecodeThread;
    private final Thread cloudThread;
    private long playTime;
    private String ossId;
    private OssMgr ossMgr;

    private boolean hasFirstDownloadFinishCalled = false;
    private boolean hasFirstDecryptFinishCalled = false;

    public CloudPlayback(Context context, Camera camera) {
        super(context, camera);

        startGetCloudFileThread();

        cloudDecodeThread = new CloudDecodeThread();
        if (!TextUtils.isEmpty(camera.desKey)) {
            cloudDecodeThread.setDesKey(camera.desKey);
        }
        cloudDecodeThread.setListener(this);
        cloudThread = new Thread(cloudDecodeThread);
        cloudThread.start();
    }

    private void startGetCloudFileThread() {
        isGetCloudThreadRunning = true;
        getCloudThread = new Thread(new GetCloudFileThread());
        getCloudThread.start();
    }


    @Override
    public void getRecordList(String time) {
        super.getRecordList(time);
        HashMap<String, String> map = new HashMap<>();
        map.put("page", "1");
        map.put("limit", "50");
        map.put("device_id", String.valueOf(camera.deviceId));
        map.put("start_timestamp", DateUtil.getTimeStamp(day.concat(" 00:00:00"),timeZone));
        map.put("end_timestamp",  DateUtil.getTimeStamp(day.concat(" 23:59:59"),timeZone));
        TGHttp.getInstance().getRecordEvent(map)
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.newThread())
                .subscribe(new ClientObserver<EventData>() {
                    @Override
                    protected void onSuccess(EventData content) {

                        // 加了这一行，这个方法可以把 相关list先清空，
                        // 避免因为同时发起了多个网络请求，而add了重复的数据
                        eventClear();
                        // 事件导入
                        List<EventMessageBean> recodeList = new ArrayList<>();
                        recodeList.addAll(content.getNormal());
                        recodeList.addAll(content.getEvent());
                        getEventList().addAll(content.getEvent());
                        sortEventMessage(recodeList);
                        addRecordTimes(recodeList);
                        timeListMerge();
                        if (playbackMediaListener != null) {
                            playbackMediaListener.onPlaybackRecordListResp(false);
                        }
                    }


                    @Override
                    protected void onResponseError(int errorCode, String errorInfo) {
                        if (playbackMediaListener != null) {
                            playbackMediaListener.onPlaybackRecordListResp(true);
                        }

                    }

                    @Override
                    protected void onOtherError(String error) {
                        if (playbackMediaListener != null) {
                            playbackMediaListener.onPlaybackRecordListResp(true);
                        }
                    }

                });

    }

    private void addRecordTimes(List<EventMessageBean> recodeList) {
        for (EventMessageBean data : recodeList) {
            if (TextUtils.isEmpty(data.getStart_time())) continue;
            int startTime = getStartTime(data);
            int endTime = DateUtil.getSecondDay(data.getEnd_time());
            TimeRuleView.TimePart part = new TimeRuleView.TimePart();
            part.startTime = startTime;
            part.endTime = endTime;
            part.eventType = data.getTag();
            part.ossId = data.getOssid();
            try {
            if (!getRecordTimes().contains(part)) {
                getRecordTimes().add(part);
            } else if (!TextUtils.isEmpty(part.eventType)) {
                getRecordTimes().remove(getRecordTimes().size() - 1);
                getRecordTimes().add(part);
            }
            }catch (IndexOutOfBoundsException e){
                    TGLog.d("IndexOutOfBoundsException = " + e.getLocalizedMessage());
                }
        }
    }

    private int getStartTime(EventMessageBean data) {
        int startTime = 0;
        String minStr = String.format("%s 00:00:00", day);
        long minTime = DateUtil.get2MillisYMDHHMMSS(minStr);
        //  开始时间 不在今天，连续录像一直没停 设置为0点为开始
        if (DateUtil.get2MillisYMDHHMMSS(data.getStart_time()) >= minTime) {
            startTime = DateUtil.getSecondDay(data.getStart_time());
            if (!TextUtils.isEmpty(data.getTag())){
                startTime -= 5;
                if (startTime<0){
                    startTime = 0;
                }
            }
        }
        return startTime;
    }

    private void sortEventMessage(List<EventMessageBean> recodeList) {
        Comparator<EventMessageBean> comparator = (eventMessage, t1) -> {
            if (!TextUtils.isEmpty(eventMessage.getStart_time()) && !TextUtils.isEmpty(t1.getStart_time())) {
                //1 后向前
                if (DateUtil.get2MillisYMDHHMMSS(t1.getStart_time()) > DateUtil.get2MillisYMDHHMMSS(eventMessage.getStart_time())) {
                    return -1;
                } else if (DateUtil.get2MillisYMDHHMMSS(t1.getStart_time()) < DateUtil.get2MillisYMDHHMMSS(eventMessage.getStart_time())) {
                    return 1;
                }
            }
            return 0;
        };
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            recodeList.sort(comparator);
        } else {
            Collections.sort(recodeList, comparator);
        }
    }

    @Override
    public void playbackRecord(long time) {
        super.playbackRecord(time);
        if (fileTimeQueue != null) {
            fileTimeQueue.offer(time);
        }
    }

    @Override
    public void startAudio() {
        isPauseAudio = false;
    }

    @Override
    public void stopAudio() {
        isPauseAudio = true;
    }

    @Override
    public void setSpeed(int speed) {
        super.setSpeed(speed);
    }

    @Override
    public void stopShow() {
        if (fileTimeQueue != null) {
            fileTimeQueue.clear();
        }
        if (cloudDecodeThread != null) {
            cloudDecodeThread.pause();
            cloudDecodeThread.clearData();
        }
    }

    @Override
    public void clear() {
        TGLog.d(TAG, "clear");
        if (ossMgr != null) {
            ossMgr.onCancelTask();
        }
        if (fileTimeQueue != null) {
            fileTimeQueue.clear();
        }
        if (cloudDecodeThread != null) {
            cloudDecodeThread.pause();
            cloudDecodeThread.clearData();
        }
    }

    @Override
    public void destroy() {
        fileTimeQueue = null;
        interruptCloudDecodeThread();
        if (ossMgr != null)
            ossMgr.onDestroy();

        interruptGetCloudThread();
    }

    private void interruptCloudDecodeThread() {
        if (cloudDecodeThread != null) {
            cloudDecodeThread.stop();
            if (!cloudThread.isInterrupted()) {
                cloudThread.interrupt();
            }
        }
    }

    private void interruptGetCloudThread() {
        isGetCloudThreadRunning = false;
        if (getCloudThread != null) {
            if (!getCloudThread.isInterrupted()) {
                getCloudThread.interrupt();
            }
            getCloudThread = null;
        }
    }


    @Override
    public void setPlaybackMediaListener(PlaybackMediaListener playbackMediaListener) {
        super.setPlaybackMediaListener(playbackMediaListener);
        if (playbackMediaListener == null) {
            cloudDecodeThread.setListener(null);
        }
    }

    @Override
    public void onCloudDecodeVideoData(AVFrames avFrames) {
        TGLog.d(TAG, "GetCloudFileThread  avFrames isPause() = " + isStop());
        if (isStop()) return;

        if (!hasFirstDecryptFinishCalled) {
            TangeVideoPlayStatistics.reportPlaybackFirstFrameDecrypt(isWifiDevice, true);
            TangeVideoPlayStatistics.resetStartTimePlayBackDecode();
            hasFirstDecryptFinishCalled = true;
        }

        if (this.playbackMediaListener != null) {
            playbackMediaListener.onPlaybackVideoData(avFrames);
        }

    }

    @Override
    public void onCloudDecodeAudioData(AVFrames avFrames) {
        if (isStop()) return;
        if (this.playbackMediaListener != null && !isPauseAudio) {
            playbackMediaListener.onPlaybackAudioData(avFrames);
        }
    }

    @Override
    public void onCloudDecodeFileStart() {
        //加5s  新下载的文件必须在范围内
        long nextTime = playTime + 5000;
        TGLog.d(TAG, "GetCloudFileThread onCloudDecodeFileStart ");
        if (isContainsTime(DateUtil.getSecondDay(nextTime)) && fileTimeQueue != null&&!isPause()) {
            fileTimeQueue.offer(nextTime);
            SystemClock.sleep(2000 / speed);
        }

    }

    @Override
    public void onCloudDecodeFileError() {

    }

    @Override
    public void onResume() {
        super.onResume();
        new Thread(new Runnable() {
            @Override
            public void run() {
                onCloudDecodeFileStart();
            }
        }).start();

    }

    @Override
    public void onOssSuccess(byte[] buf, long time) {
        cloudDecodeThread.resume();
        ossMgr.initErrorCount();
        TGLog.d("GetCloudFileThread onGetSuccess ");

        if (!hasFirstDownloadFinishCalled) {
            TangeVideoPlayStatistics.reportPlaybackFirstFrameDownload(isWifiDevice, true);
            TangeVideoPlayStatistics.resetStartTimePlayBackDecrypt();
            cloudDecodeThread.setWifiDevice(isWifiDevice);

            hasFirstDownloadFinishCalled = true;
        }

        if (cloudDecodeThread != null) {
            cloudDecodeThread.addData(buf);
        }
    }

    @SuppressLint("DefaultLocale")
    @Override
    public void onOssFailed(String error, int code) {
        TGLog.d("onOssFailed error " + code);
        ossMgr.addErrorCount();
        if (code != 403) {
            if (this.playbackMediaListener != null) {
                playbackMediaListener.onPlaybackOssFailed(ossMgr.getDownloadTime(), ossMgr.getErrorCount());
                if (ossMgr.isMaxErrorCount()){
                    ossMgr.initErrorCount();
                }
            }
        }

        TGLog.e(TAG, String.format("云文件下载失败uid: %s 时间：%s eror:%s code: %d", camera.uid, DateUtil.generateTime(playTime), error,code));
    }

    @Override
    public void onOssOtherError(String error) {

    }

    @Override
    public void onOssInitSuccess() {
        ossMgr.getFile(playTime);
        ossMgr.initErrorCount();
    }

    private class GetCloudFileThread implements Runnable {
        @Override
        public void run() {
            while (isGetCloudThreadRunning) {
                try {
                    if (fileTimeQueue == null) {
                        SystemClock.sleep(500);
                        continue;
                    }
                    playTime = fileTimeQueue.take();
                    int partTime = DateUtil.getSecondDay(playTime);
                    String curOssId = getPartOssId(partTime);
                    if (TextUtils.isEmpty(curOssId)) curOssId = "";
                    TGLog.d(TAG, " GetCloudFileThread curOssId:%s newOssId: %s  %d :%s", ossId, curOssId, partTime, DateUtil.formatTimeHHmmss(partTime));
                    if (!TextUtils.equals(ossId, curOssId)) {
                        ossId = curOssId;
                        ossMgr = new OssMgr(getContext(),String.valueOf(camera.deviceId),ossId,CloudPlayback.this);
                    } else if (ossMgr != null) {
                        ossMgr.getFile(playTime);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            TGLog.d(TAG, "GetCloudFileThread exit");
        }
    }


}
